Notes
{labels: 'NewtDev_d}
ERASE! // No empty lines between erase! and first item
aComments
func() begin end /*
- Last compilation 960421
- Compiles under NewtDev 3.3fN + Pack 3.3cN on upgraded OMP w/ OS1.3(414313)
- Based on code by Konrad Hinsen, hinsen@ere.umontreal.ca; no|SoftwareGmbH, Ritzstr. 13, D-54595 Pruem, Germany.
- See helpbook for more info.
- ListExtras is utility for determining app/owner symbols of installed apps.
- View on screen's right edge after build is an artifact that goes away when screen refreshed.
- Scratchpad useful even under NOS 2.0 -- character entry in long paragraphs still slow (at least in my trial); each NewtDev source page is one "paragraph."
- The default placement covers the name of the month in the Dates calendar (Konrad's original placement was on the other side).  If you'd prefer a different location simply move the view after a reboot; recompile the code to permanently change the location.
- For paraV to save its text in the NewtDev environment requires access to an installed app's savedText slot.

*/
-----
aTest
func() begin end /*

*/
-----
init
func()  // :init()    // re-eval after changes
begin
:defConst('kAppSymbol, '|noButts:bc|);
:defConst('kGraffitiSym, '|Graffiti:Palm|);
:defConst('k2brdr, 12);  //2x width of view border
:defConst('kDragLip, 5);  //drag margin
end

-----
noButts
//:doObj('buildCO,'noButts)
//:doObj('add,'noButts)
//:saveApp('noButts)
//:BuildFolderLib('noButts)
//noButts:open()
{_proto: protoFloater,

// put button bar in the top right corner (for left corner, change L RelB to +, vjParH to left, and invert bounds calc)
viewBounds: RelBounds (-2, 2, 0, 12),
viewJustify: vjParentRightH+vjParentTopV,
viewFormat: vfFillWhite+vfFrameBlack+vfPen*1+vfInset*1+vfRound*0,

savedText: "", //for ScratchPad
viewQuitScript: func()  savedText:= helpView:= nil,

viewSetupFormScript: func() begin
	// calculate correct width depending on number and size of buttons, less 1 for each non-button child
	local nonButns := 1;
	local bounds := Clone(viewBounds);
	if self.stepChildren exists then begin
		// bounds.right := bounds.left + //for left side
		bounds.left := bounds.right -
			(Length(stepChildren)-nonButns) *
			protoBarButton.viewBounds.right;
			self.viewBounds := bounds;		
		end; 
	end,

// Platform function
viewIsOpen: kViewIsOpenFunc,

_package: {
// Make sure it doesn't close automatically
	autoClose: 'noAutoClose,
	shortTitle: "noButts",
	devSignature: "bc",
	version: 099,
	copyright: "(c) 1995, no|Software GmbH; 1996, Bill Cooper",

	installScript: func(removeFrame) begin
	// Close card slip if open
		AddDeferredAction(func()
			if GetRoot().backupSlip.viewCObject
			<> nil then
				GetRoot().backupSlip:close(), []);
	// Open automatically
		AddDeferredAction(func()
			GetRoot().(kAppSymbol):open(), []);
	end,
	}, //end of package
}
-----
noButts.protoBarButton
{_proto: protoStaticText,
viewBounds: {left:0, right:12, top:0, bottom:0},
viewJustify: vjParentFullV + vjParentLeftH + vjSiblingRightH + vjCenterH + vjCenterV,
viewFormat: vfFillWhite + vfFrameMatte + vfPen*1 + vfInset*1,
viewFlags: vVisible + vReadonly + vClickable,
text: " ",
viewFont: ROM_fontSystem9, 

viewClickScript: func(unit) begin
	InkOff(unit);
	count := 0;
	viewUnit := unit;
	if :TrackHilite(unit) then begin
		:Hilite(nil);
		if count < dragCount then
			:?buttonClickScript();
		end;
	true //stop others from handling click
	end,

count: 0,
dragCount: 20,
viewUnit: nil,
buttonPressedScript: func() begin //dragging
	count := count + 1;
	if count = dragCount then begin
		:Parent():Drag(viewUnit,nil);
		:Parent():Dirty();
		end;
	end,

//these methods support buttons that popup and postkeys

buttonPressedScriptPopUp: func(me,menu) begin
	count := count + 1;
	if count = dragCount then
		DoPopup(menu,0,0,me);
	end,

postTheText: func(txt)
	PostKeyString('viewFrontKey,txt),
pickActionScript2: func(me,a,b) begin
	setvalue(me,'text,a); //set button text
	me.bThing:= b; //set post string or app symbol
	me:Hilite(nil);
	end,
}
-----
noButts.help~
{helpBook: :helpBookTemplate(),
helpView: nil, //slot holds builtContext
buildHelpBook: func() begin
	self.helpView:= BuildContext({
		_proto: GetRoot().TinyTim._proto,
		bookRef: helpBook});
	GetRoot().TinyTim:close(); //in case open
	helpView:openManual(helpBook);
	end, 
}
-----
noButts+aCharButton~
{_proto: protoBarButton,
text: "d",
bThing: "\u0008",
menu1: ["d","s","t", ], //button text
menu2: ["\u0008"," ","\t",], //post
menu3: ["delete","space","tab",], //menu
buttonClickScript: func() 
	:postTheText(bThing),
buttonPressedScript: func()
	:buttonPressedScriptPopUp(self,menu3),
pickActionScript: func(index) begin
	:pickActionScript2(self,menu1[index], menu2[index]);
	:postTheText(bThing);
	end,
}
-----
noButts+aReturnButton~
{_proto: protoBarButton,
text: "r",
buttonClickScript: func()
begin
   PostKeyString('viewFrontKey, "\n")
end,
}
-----
noButts+azBulletButton~
{_proto: protoBarButton,
text: "\u2022", //bullet char
bThing: "\n\u2022\u ", //current post string
menu1: ["\u2022","-",], //button text
menu2: ["\n\u2022\u ","\n- ",], //post strings; note space after char
menu3: ["\u2022","-",], //menu strings
buttonClickScript: func() 
	:postTheText(bThing),
buttonPressedScript: func()
	:buttonPressedScriptPopUp(self,menu3),
pickActionScript: func(index) begin
	:pickActionScript2(self,menu1[index], menu2[index]);
	:postTheText(bThing);
	end,
}
-----
noButts.helpBook+page01
.# this is a comment
.subject 1
Credits et al
.story
noButts.  by Bill Cooper.  v0.99, 1996.04
	Based on "noButtons" by Konrad Hinton, 1995.  Free software "copylefted" under the General Public License of the Free Software Foundation.  Modify, use and pass on this software as you wish, but always provide the source code if asked.  As a courtesy, credit previous authors in your code.
	Developed on the Newton with NewtDev, Steve Weyer's development system (weyer@netaxs.com).
	Contact the author at bwcooper@ ucdavis.edu, or P.O. Box 72781, 95617.

-----
noButts.helpBook+page02
.subject 1
The Button Bar
.story
	The button bar is positioned in the upper right corner when first opened.  Press the " L " button for a second or so, then drag the bar elsewhere if desired.
	Some buttons have both a tap and a press behavior.  Tapping the button performs an action.  Pressing the button pops up a menu of options.  Selecting a menu item performs the chosen action and makes that the button's new function.
-----
noButts.helpBook+page03
.subject 1
The Buttons
.story
	Tapping the first button from the left (initially labeled " d " for delete) inserts a character at the insertion point (also useful for erasing selected text).  Pressing this button pops up an options menu.
	Tapping the button labeled " r " inserts a newline (return) character.  This button has no menu.
	Tapping the third button from the left (a bullet) inserts a newline and a bullet character.  Press this button for a menu.
	The fourth button opens or closes the alphanumeric keyboard.  Graffiti appears in the menu if installed.
-----
noButts.helpBook+page04
.subject 1
Launch Menu
.story
	The " L " or Launch button menu has four sections.  The first lists "quick pick" applications.  If Replacer or Ruler is installed they will appear here.
	The second section shows - and lets you switch between - currently running applications.
	The third section lists several utilities.  One of them, Scatchpad, is described in the next topic.
	The fourth section is what you are reading.
-----
noButts.helpBook+page05
.subject 1
Scatchpad 
.story
	Scatchpad is a draggable, writeable view.  On it you can write small, quickly editable pieces of text you can paste into other views - useful when editing and adding text in long notes
	Clear the view with the Clr button; select all text with All.  Drag the selected text into the Notepad or use the clipboard.  Shapes are not supported.  Text is retained by the view when closed.
-----
noButts+KeyboardButton~
{_proto: protoBarButton,
text: "K",
bThing: 'alphaKeyboard,
menu1: ["K","G",],
menu2: ['alphaKeyboard, kGraffitiSym,],
menu3a: ["alphaKbd","Graffiti",],
menu3b: ["alphaKbd",], //not a generic solution

buttonPressedScript: func()
	:buttonPressedScriptPopUp(self,
		if GetRoot().(kGraffitiSym) exists then menu3a
		else menu3b),
toggleApp: func(sym) begin
	local k := GetRoot().(sym);
	if :ViewIsOpen(k) then k:Close()
	else k:Open();
	end,
buttonClickScript: func() 
	:toggleApp(bThing),
pickActionScript: func(index) begin
	:pickActionScript2(self,menu1[index], menu2[index]);
	:toggleApp(bThing);
	end,
}
-----
noButts+LaunchButton
{_proto: protoBarButton,
text: "L",

quickApps: ['|NewtDevEnv:TKnollSys|, 'calculator, 'backupSlip, 'stylePalette, '|Ruler:bc|, '|Replacer:bc|,],  //'dockerChooser,
//why does listExtras show card instead of backupSlip?

appList: [],
firstOpen: 0,
lastOpen: 0,
extrasEntry: nil,

// This function finds the element in 
// GetGlobals().Extras that corresponds to
// a given application symbol.
findExtrasEntry: func(sym) begin
	local app;
	if extrasEntry = nil then begin
		foreach app in GetGlobals().Extras do		
			if app.app = sym then
				break extrasEntry := app;
		end; 
	extrasEntry;
	end,

// Construct the menu entry for an app.
findAppName: func(sym) begin
	if sym = 'backupSlip then "Card" else //handle exception for backupSlip/card
	if GetRoot().(sym).title exists then
		GetRoot().(sym).title;
	else if :findExtrasEntry(sym) then
		extrasEntry.text;
	else
		SPrintObject(sym);
	end,

// Find the app symbol for a given view.
findAppSymbol: func(view)
	if Band(view.viewFlags,4)=0 then nil 
	else view.appSymbol,

viewQuitScript: func()
	appList:= firstOpen:= lastOpen:= extrasEntry:= nil,
}
-----
noButts.LaunchButton.buttonClickScript
func() begin
	local app, view, isArchived;
	local menu := [];
	appList := [];

// make list of quick-access apps
	foreach app in quickApps do begin		extrasEntry := nil;
		if :findExtrasEntry(app).archived exists then
			isArchived:= true
			else isArchived:= nil;  // workaround problem w/ keyboard and like returning nil path
		if (HasSlot(GetRoot(),app) and not
			:viewIsOpen(GetRoot().(app))) or
			isArchived then
		begin
			AddArraySlot(appList,app);
			AddArraySlot(menu,
				:findAppName(app));
		end;
	end;
	if Length(appList) > 0 then begin
		AddArraySlot(appList,nil);
		AddArraySlot(menu,'pickSeparator);
	end;

// make list of open apps
	firstOpen := Length(appList);
	foreach view in
		GetRoot():childViewFrames() do begin
		app := :findAppSymbol(view);
		if not app = nil then begin
			AddArraySlot(appList,app);
			AddArraySlot(menu,
				:findAppName(app));
		end;
	end;
	lastOpen := Length(appList) - 1;
	if Length(appList) > 0 then begin
		AddArraySlot(appList,nil);
		AddArraySlot(menu,'pickSeparator);
	end;

// add user funcs
	AddArraySlot(appList,'reboot);
	AddArraySlot(menu,"Reboot"); 
	AddArraySlot(appList,'showMemFree);
	AddArraySlot(menu,"showMemFree");
	AddArraySlot(appList,'doTextFnG);
	AddArraySlot(menu,"Scatchpad"); 

//Add info pick
	AddArraySlot(appList,nil);
	AddArraySlot(menu,'pickSeparator);	
	AddArraySlot(appList,'doInfoFloatNGo);
	AddArraySlot(menu,"Info"); 

// open the popup menu
	if Length(menu) > 0 then
		DoPopup(menu,0,0,self);
end
-----
noButts.LaunchButton.pickActionScript
func(index) begin
	local i,widget;
	extrasEntry := nil;

// reboot: ask for confirmation first
	if appList[index] = 'reboot then
		GetRoot():confirm("noButts",
			"Do you really want to reboot?",
			self, 'reboot)
	else

// other usr funcs 
	if appList[index] = 'showMemFree then
		begin 
			playsound(@102);
			DoPopup([:showMemFree()],12,12,nil);
		end
	else
	if appList[index] = 'doInfoFloatNGo then
		:buildHelpBook()
		//:doInfoFloatNGo();
	else
	if appList[index] = 'doTextFnG then
		begin
			appArea := getAppParams();
			: doTextFnG();
		end

// open application: hide those above
	else if index >= firstOpen then begin
		SetKeyView(nil,nil);
		for i := firstOpen to index do
			GetRoot().(appList[i]):show();
		for i := index+1 to lastOpen do
			GetRoot().(appList[i]):hide();
	end else

// open the selected application
	if GetRoot().(appList[index]) exists then 

GetRoot().(appList[index]):open();
	else begin
		widget := Clone(
			:findExtrasEntry(appList[index]));
		widget._parent :=
			GetRoot().extrasDrawer;
		widget._proto :=
			GetRoot().extrasDrawer.baseExtra;
		AddDeferredAction(func(x)
			x:buttonClickScript(), [widget]);
	end;
end
-----
noButts.LaunchButton.userFuncs~
{
showMemFree:func() begin
	gc();
	"after gc():"&NumberStr(stats()); 
	end,

reboot: func(flag)  if flag then Reboot(),

doTextFnG:func() begin
	if zTextFloatNGo exists then 
		begin
			zTextFloatNGo:= BuildContext( zTextFloatNGo._proto);
			zTextFloatNGo:Open();
		end;
	end,
}
-----
noButts+zTextFloatNGo
{_proto: protoFloatNGo,
viewFlags:vClickable+vFloating, // keep this dragable view invis until open or bizarre compile!

viewSetupDoneScript: func() begin
	if paraV exists then
setValue(paraV,'text,GetRoot().(kAppSymbol).savedText);
end,

dragBounds: nil,
viewSetupFormScript:func() begin
	local b:= GetAppParams();
	local xa:= b.appAreaWidth;
	local ya:= b.appAreaHeight;
	local xb:= min(240,xa)-k2brdr; //less 6 pixel border x2
	local yb:= min(162,ya)-k2brdr;
	dragBounds:= SetBounds(0-xb+kDragLip, 0-yb+kDragLip, xa+xb-kDragLip, ya+yb-kDragLip);
	self.viewbounds := RelBounds(0,20,xb,yb)
	end,

clickAbove:nil, //flg set by paraV if clicked 
viewQuitscript:func()  clickAbove:=nil,

viewClickScript:func(unit)
	if clickAbove then begin
		clickAbove := nil; // clr always
		nil // msg not handled, reverts to clParaV receiver
		end
	else begin 
		:Drag(unit,dragBounds); 
		clickAbove := nil; 
		true;
		end,
}
-----
noButts.zTextFloatNGo+allbut
{_proto: protoTextButton,
text: "All", 
viewbounds:Relbounds(45,138,25,9),
/* problem centering button text when using view justify flags
viewBounds:{left:35,top:-12,right:55,bottom:-3},
viewJustify: vjParentLeftH+vjParentBottomV, */
buttonClickScript: func() begin 
	paraV:SetHilite(0,StrLen(paraV.text),nil);
	end,
}
-----
noButts.zTextFloatNGo+clrbut
{_proto: protoTextButton,
text: "Clr", 
viewbounds:Relbounds(5,138,25,9),
//viewBounds:{left:5,top:-12,right:25,bottom:-3},
//viewJustify: vjParentLeftH+vjParentBottomV,
buttonClickScript: func() begin 
	setvalue(paraV,'text,"");
	end,
}
-----
noButts.zTextFloatNGo+paraV
{viewClass: clParagraphView,
viewBounds: {left:3, top:5, right:-3, bottom:-17},
viewJustify: vjParentFullH+vjParentFullV,
text:nil, 
viewFont: fancyFont10,
viewFlags: vVisible + vClickable + vGesturesAllowed + vCharsAllowed + vNumbersAllowed,
viewFormat: vfFillWhite + vfFrameBlack + vfPen*1 + vfLinesGray,
viewLineSpacing: 18, 
tabs: [36,72,108,144,180,216],
viewClickScript:func(unit) begin
	clickAbove:=true; // flag to parent
	nil; // msg moves up parent chain
	end,
viewQuitScript: func() begin
	GetRoot().(kAppSymbol).savedText:=text;
	//setValue(kNobutSymbol,'savedText,text);
	end,
}
-----
x_listExtras
//:listExtras()
func()
begin
	local app;
	foreach app in GetGlobals().extras do
		print(app.text & ":" && app.app);
end 

-----
x_noButts+GraffitiButton~
{_proto: protoBarButton,
text: "G",
buttonClickScript: func()
begin
	local g := GetRoot().|Graffiti:Palm|;
	local w;
	if :ViewIsOpen(g) then
		g:Close();
	else begin
		//w:= g.viewBounds.right - g.viewBounds.left;	
		g:Open();
		//if w > 80 then
			//g.stepChildren[17]
				//:buttonClickScript();
	end;
end,
}
-----
x_noButts+TopAppButton~
{_proto: protoBarButton,
text: "T",

actionTable: {
	|NewtDevEnv:TKnollSys|: func(view)
	begin
		view.exprKbd:toggle();
	end,

	paperRoll: func(view)
	begin
		GetRoot().stylePalette:open();
	end,

	Names: func(view)
	begin
		GetRoot().alphaKbd:open();
	end
},

buttonClickScript: func() begin
	local topView :=
		GetView('viewFrontMostApp);
	local sym := topView.appSymbol;
	if HasSlot(self.actionTable,sym) then
		Perform(self.actionTable,sym,
			[topView]);
end,
}
-----
BYE!
